home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 5 / QRZ Ham Radio Callsign Database - Volume 5.iso / files / tcpip / amiga / asrc29p.lha / domain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-29  |  19.4 KB  |  901 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include "global.h"
  4. #include "mbuf.h"
  5. #include "timer.h"
  6. #include "netuser.h"
  7. #include "socket.h"
  8. #include "cmdparse.h"
  9. #include "proc.h"
  10. #include "domain.h"
  11. #include "commands.h"
  12.  
  13. static struct dserver *Dlist;        /* List of potential servers */
  14. static struct dserver *Dserver;        /* Current one being used */
  15. static char *Dsuffix;            /* Default suffix for names without periods */
  16. static int Ddebug = 0;
  17. static char *Dtypes[] = {
  18.     "",
  19.     "A",
  20.     "NS",
  21.     "MD",
  22.     "MF",
  23.     "CNAME",
  24.     "SOA",
  25.     "MB",
  26.     "MG",
  27.     "MR",
  28.     "NULL",
  29.     "WKS",
  30.     "PTR",
  31.     "HINFO",
  32.     "MINFO",
  33.     "MX",
  34.     "TXT"
  35. };
  36. static int Ndtypes = 17;
  37. static char delim[] = " \t\r\n";
  38. static struct {
  39.     char *name;
  40.     int32 address;
  41. } cache;
  42.  
  43. static struct rr *dfind __ARGS((FILE *dbase,char *name,int type));
  44. static int doadds __ARGS((int argc,char *argv[],void *p));
  45. static int dodropds __ARGS((int argc,char *argv[],void *p));
  46. static int dolistds __ARGS((int argc,char *argv[],void *p));
  47. static int dosuffix __ARGS((int argc,char *argv[],void *p));
  48. static int dodtrace __ARGS((int argc,char *argv[],void *p));
  49. static void dumpdomain __ARGS((struct dhdr *dhdr,int32 rtt));
  50. static void free_dhdr __ARGS((struct dhdr *dp));
  51. static void free_qu __ARGS((struct quest *qp));
  52. static void free_rr __ARGS((struct rr *rrp));
  53. static struct rr *getrr __ARGS((FILE *fp));
  54. static int isaddr __ARGS((char *s));
  55. static void cache_response __ARGS((struct dhdr *dhdr));
  56. static void putrr __ARGS((FILE *fp,struct rr *rrp));
  57. static int res_mkquery __ARGS((int16 op,char *dname,int16 class,int16 type,
  58.     char *data,int16 datalen,int16 newrr,char *buffer,int16 buflen));
  59. static int rrcmp __ARGS((struct rr *rr1,struct rr *rr2));
  60. static int sendquery __ARGS((int32 server,char *name,int type,int32 timeout,
  61.     struct mbuf **bpp));
  62.  
  63. static struct cmds Dcmds[] = {
  64.     "addserver",    doadds,        0, 2, NULLCHAR,
  65.     "dropserver",    dodropds,    0, 2, NULLCHAR,
  66.     "listservers",    dolistds,    0, 0, NULLCHAR,
  67.     "suffix",    dosuffix,    0, 0, NULLCHAR,
  68.     "trace",    dodtrace,    0, 0, NULLCHAR,
  69.     NULLCHAR,
  70. };
  71.  
  72. static int
  73. dodtrace(argc,argv,p)
  74. int argc;
  75. char *argv[];
  76. void *p;
  77. {
  78.     return setbool(&Ddebug,"Domain trace",argc,argv);
  79. }
  80.  
  81. int
  82. dodomain(argc,argv,p)
  83. int argc;
  84. char *argv[];
  85. void *p;
  86. {
  87.     if(argc == 1)
  88.         return dolistds(argc,argv,p);
  89.     return subcmd(Dcmds,argc,argv,p);    
  90. }
  91.  
  92. static int
  93. dosuffix(argc,argv,p)
  94. int argc;
  95. char *argv[];
  96. void *p;
  97. {
  98.     if(argc < 2){
  99.         if(Dsuffix != NULLCHAR)
  100.             tprintf("%s\n",Dsuffix);
  101.         return 0;
  102.     }
  103.     free(Dsuffix);
  104.     Dsuffix = strdup(argv[1]);
  105.     return 0;
  106. }
  107. static int
  108. doadds(argc,argv,p)
  109. int argc;
  110. char *argv[];
  111. void *p;
  112. {
  113.     struct dserver *dp;
  114.     int32 address;
  115.  
  116.     if((address = resolve(argv[1])) == 0){
  117.         tprintf("Resolver %s unknown\n",argv[1]);
  118.         return 1;
  119.     }
  120.     dp = (struct dserver *)callocw(1,sizeof(struct dserver));
  121.     dp->address = address;
  122.     dp->srtt = (5L * 1000) / MSPTICK; /* About 5 sec */
  123.     dp->mdev = 0;
  124.     dp->timeout = 2 * dp->mdev + dp->srtt + 3;
  125.     dp->next = Dlist;
  126.     if(dp->next != NULLDOM)
  127.         dp->next->prev = dp;
  128.     Dlist = dp;
  129.     Dserver = dp;    /* Make this the first one we try next */
  130.     return 0;
  131. }
  132. static int
  133. dodropds(argc,argv,p)
  134. int argc;
  135. char *argv[];
  136. void *p;
  137. {
  138.     struct dserver *dp;
  139.     int32 addr;
  140.  
  141.     addr = resolve(argv[1]);
  142.     for(dp = Dlist;dp != NULLDOM;dp = dp->next)
  143.         if(addr == dp->address)
  144.             break;
  145.  
  146.     if(dp == NULLDOM){
  147.         tprintf("Not found\n");
  148.         return 1;
  149.     }
  150.     if(dp->prev != NULLDOM)
  151.         dp->prev->next = dp->next;
  152.     else
  153.         Dlist = dp->next;
  154.     if(dp->next != NULLDOM)
  155.         dp->next->prev = dp->prev;
  156.  
  157.     if(Dserver == dp)
  158.         Dserver = Dlist;
  159.     free((char *)dp);
  160.     return 0;
  161. }
  162. static int
  163. dolistds(argc,argv,p)
  164. int argc;
  165. char *argv[];
  166. void *p;
  167. {
  168.     register struct dserver *dp;
  169.  
  170.     tprintf("Server address      srtt    mdev    timeout\
  171.  queries responses\n");
  172.     for(dp = Dlist;dp != NULLDOM;dp = dp->next){
  173.         tprintf("%-20s%-8lu%-8lu%-8lu%-8lu%-8lu\n",
  174.          inet_ntoa(dp->address),
  175.          dp->srtt * MSPTICK,
  176.          dp->mdev * MSPTICK,
  177.          dp->timeout * MSPTICK,
  178.          dp->queries,dp->responses);
  179.     }
  180.     return 0;
  181. }
  182.  
  183. /* Search local domain file, starting at current position,
  184.  * for resource record of specified type.
  185.  * If a record is found, the domain file pointer is left just after it. If
  186.  * not, it is left at end of file.
  187.  */
  188. static struct rr *
  189. dfind(dbase,name,type)
  190. FILE *dbase;
  191. char *name;
  192. int type;
  193. {
  194.     struct rr *rrp;
  195.     int nlen;
  196.  
  197.     while((rrp = getrr(dbase)) != NULLRR){
  198.         if( rrp->name
  199.          && (nlen = strlen(name)) == strlen(rrp->name)
  200.          && strnicmp(name,rrp->name,nlen) == 0
  201.          && rrp->class == CLASS_IN
  202.          && (type == TYPE_ANY || rrp->type == type))
  203.             break;
  204.         free_rr(rrp);
  205.         pwait(NULL);    /* Give up CPU for a while, this is slow */
  206.     }
  207.     return rrp;
  208. }
  209. static struct rr *
  210. getrr(fp)
  211. FILE *fp;
  212. {
  213.     char *line,*strtok();
  214.     struct rr *rrp;
  215.     char *name,*ttl,*class,*type,*data;
  216.     int i;
  217.  
  218.     line = mallocw(256);
  219.     /* Search file */
  220.     while(fgets(line,256,fp),!feof(fp)){
  221.         if(line[0] != '#')
  222.             break;
  223.     }
  224.     if(feof(fp)){
  225.         free(line);
  226.         return NULLRR;
  227.     }
  228.      rrp = (struct rr *)callocw(1,sizeof(struct rr));
  229.     name = strtok(line,delim);
  230.     ttl = strtok(NULLCHAR,delim);
  231.     class = strtok(NULLCHAR,delim);
  232.     type = strtok(NULLCHAR,delim);
  233.     data = strtok(NULLCHAR,delim);
  234.     
  235.     if( ! type ) {
  236.         free( line );
  237.         return( rrp );
  238.     }
  239.  
  240.     i = strlen(name);
  241.     if(name[i-1] != '.'){
  242.         /* Tack on a trailing period if it's not there */
  243.         rrp->name = mallocw(i+2);
  244.         strcpy(rrp->name,name);
  245.         strcat(rrp->name,".");
  246.     } else 
  247.         rrp->name = strdup(name);
  248.     
  249.     if(!isdigit(ttl[0])){
  250.         /* Optional ttl field is missing; slide the other fields over */
  251.         data = type;
  252.         type = class;
  253.         class = ttl;
  254.         ttl = NULLCHAR;
  255.     } else {
  256.         rrp->ttl = atol(ttl);
  257.     }
  258.     for(i=0;i<NRLIST;i++){
  259.         if(strcmp(type,Dtypes[i]) == 0){
  260.             rrp->type = i;
  261.             break;
  262.         }
  263.     }
  264.     if(strcmp(class,"IN") == 0)
  265.         rrp->class = CLASS_IN;
  266.  
  267.     if(data == NULLCHAR){
  268.         /* Empty record, just return */
  269.         free(line);
  270.         return rrp;
  271.     }
  272.     switch(rrp->type){
  273.     case TYPE_CNAME:
  274.     case TYPE_MB:
  275.     case TYPE_MG:
  276.     case TYPE_MR:
  277.     case TYPE_NS:
  278.     case TYPE_PTR:
  279.     case TYPE_TXT:
  280.         rrp->rdlength = strlen(data);
  281.         rrp->rdata.name = strdup(data);
  282.         break;
  283.     case TYPE_A:
  284.         rrp->rdlength = 4;
  285.         rrp->rdata.addr = aton(data);
  286.         break;
  287.     case TYPE_HINFO:
  288.         rrp->rdlength = strlen(data);
  289.         rrp->rdata.hinfo.cpu = strdup(data);
  290.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  291.             rrp->rdlength += strlen(data);
  292.             rrp->rdata.hinfo.os = strdup(data);
  293.         }
  294.         break;
  295.     case TYPE_MX:
  296.         rrp->rdata.mx.pref = atoi(data);
  297.         rrp->rdlength = 2;
  298.  
  299.         /* Get domain name of exchanger */
  300.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  301.             rrp->rdlength += strlen(data);
  302.             rrp->rdata.mx.exch = strdup(data);
  303.         }
  304.         break;
  305.     case TYPE_SOA:
  306.         /* Get domain name of master name server */
  307.         rrp->rdlength = strlen(data);
  308.         rrp->rdata.soa.mname = strdup(data);
  309.  
  310.         /* Get domain name of irresponsible person */
  311.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  312.             rrp->rdata.soa.rname = strdup(data);
  313.             rrp->rdlength += strlen(data);
  314.         }
  315.         data = strtok(NULLCHAR,delim);
  316.         rrp->rdata.soa.serial = atol(data);
  317.         data = strtok(NULLCHAR,delim);
  318.         rrp->rdata.soa.refresh = atol(data);
  319.         data = strtok(NULLCHAR,delim);
  320.         rrp->rdata.soa.retry = atol(data);
  321.         data = strtok(NULLCHAR,delim);
  322.         rrp->rdata.soa.expire = atol(data);
  323.         data = strtok(NULLCHAR,delim);
  324.         rrp->rdata.soa.minimum = atol(data);
  325.         rrp->rdlength += 20;
  326.         break;
  327.     }
  328.     free(line);
  329.     return rrp;
  330. }
  331. /* Search for address record in local database, looking first for PTR
  332.  * and CNAME records. Return values:
  333.  *  0xffffffff    Not found (domain name may exist, but we don't know yet)
  334.  *  0        Domain name definitely doesn't exist (we have a null record)
  335.  */
  336. int32
  337. dresolve(name)
  338. char *name;
  339. {
  340.     register struct rr *rrp;
  341.     char *sname,*tmp;
  342.     int32 addr;
  343.     FILE *dbase;
  344.     int crecurse = 0;
  345.     int found = 0;
  346.  
  347.     if(cache.name != NULLCHAR && strcmp(cache.name,name) == 0)
  348.         return cache.address;
  349.  
  350.     if((dbase = fopen(Dfile,READ_TEXT)) == NULLFILE)
  351.         return 0xffffffff;
  352.  
  353.     sname = strdup(name);
  354.  
  355.     while(!found && (rrp = dfind(dbase,sname,TYPE_ANY)) != NULLRR){
  356.         switch(rrp->type){
  357.         case TYPE_A:
  358.             /* All set! */
  359.             found++;
  360.             if(rrp->rdlength == 0)
  361.                 addr = 0;    /* Neg response */
  362.             else
  363.                 addr = rrp->rdata.addr;
  364.             break;
  365.         case TYPE_CNAME:
  366.         case TYPE_PTR:
  367.             if(++crecurse == MAXCNAME){
  368.                 /* Too many CNAME recursions */
  369.                 found++;
  370.                 break;
  371.             }
  372.             /* Look for what it points to */
  373.             tmp = strdup(rrp->rdata.name);
  374.             free(sname);
  375.             sname = tmp;
  376.             rewind(dbase);    /* Start again */
  377.             break;
  378.         }
  379.         free_rr(rrp);
  380.     }
  381. done:    fclose(dbase);
  382.     if(found){
  383.         free(cache.name);
  384.         cache.name = strdup(name);
  385.         cache.address = addr;
  386.     } else
  387.         addr = 0xffffffff;
  388.     free(sname);
  389.     return addr;
  390. }
  391.  
  392. /* Main entry point for domain name -> address resolution. Returns 0 if
  393.  * name is definitely not valid.
  394.  */
  395. int32
  396. resolve(name)
  397. char *name;
  398. {
  399.     int32 addr;
  400.     struct dhdr dhdr;
  401.     struct dserver *dp = Dserver;
  402.     char *sname,*tmp;
  403.     int len,i;
  404.     int32 rtt,abserr;
  405.     struct mbuf *bp;
  406.     struct rr *rrp;
  407.     int crecurse = 0;
  408.  
  409.     if(name == NULLCHAR)
  410.         return 0;
  411.  
  412.     if(*name == '[')
  413.         return aton(name + 1);
  414.  
  415.     if(isaddr(name))
  416.         return aton(name);
  417.  
  418.  
  419.     sname = strdup(name);
  420.     if(strchr(sname,'.') == NULLCHAR && Dsuffix != NULLCHAR){
  421.         /* Append default suffix */
  422.         tmp = mallocw(strlen(sname)+strlen(Dsuffix)+2);
  423.         sprintf(tmp,"%s.%s",sname,Dsuffix);
  424.         free(sname);
  425.         sname = tmp;
  426.     }
  427.     if(sname[strlen(sname)-1] != '.'){
  428.         /* Append trailing dot */
  429.         tmp = mallocw(strlen(sname)+2);
  430.         sprintf(tmp,"%s.",sname);
  431.         free(sname);
  432.         sname = tmp;
  433.     }
  434.     while((addr = dresolve(sname)) == 0xffffffff){
  435.         /* Not found in local file. Query the domain servers. */
  436.         if(dp == NULLDOM)
  437.             break;        /* no servers! */
  438.         for(;;){
  439.             dp->queries++;
  440.             len = sendquery(dp->address,sname,TYPE_A,dp->timeout,&bp);
  441.             if(len > 0)
  442.                 break;    /* Got a response */
  443.             if(errno == EABORT){
  444.                 addr = 0;    /* Killed by "reset" command */
  445.                 break;
  446.             }
  447.             /* Timeout; back off this one and try another server */
  448.             dp->timeout <<= 1;
  449.             if((dp = dp->next) == NULLDOM)
  450.                 dp = Dlist;
  451.         }
  452.         if(len <= 0)
  453.             break;
  454.         dp->responses++;
  455.         ntohdomain(&dhdr,&bp);    /* Convert response to local format */
  456.  
  457.         /* Compute and update the round trip time */
  458.         rtt = (int32) ((int16)Clock - dhdr.id);
  459.         abserr = rtt > dp->srtt ? rtt - dp->srtt : dp->srtt - rtt;
  460.         dp->srtt = ((AGAIN-1) * dp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
  461.         dp->mdev = ((DGAIN-1) * dp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
  462.         dp->timeout = 2 * dp->mdev + dp->srtt + 3;
  463.  
  464.         if(Ddebug)
  465.             dumpdomain(&dhdr,rtt);
  466.         cache_response(&dhdr);    /* Add records to local disk file */
  467.         /* Look for an answer in this response */
  468.         for(i=0;i<dhdr.ancount;i++){
  469.             rrp = dhdr.ans[i];
  470.             if(strnicmp(rrp->name,sname,strlen(sname)) != 0)
  471.                 continue;
  472.             /* Got one! */
  473.             switch(rrp->type){
  474.             case TYPE_CNAME:
  475.                 /* Change the query name to the cname
  476.                  * and go back again
  477.                  */
  478.                 if(++crecurse == MAXCNAME){
  479.                     /* Too many CNAME recursions */
  480.                     addr = 0;
  481.                     break;
  482.                 }
  483.                 free(sname);
  484.                 sname = strdup(rrp->rdata.name);
  485.                 /* Go back and rescan the response */
  486.                 i = -1;
  487.                 continue;
  488.             case TYPE_A:
  489.                 if(rrp->rdlength == 0)
  490.                     addr = 0;
  491.                 else
  492.                     addr = rrp->rdata.addr;
  493.                 break;
  494.             }
  495.             break;
  496.         }
  497.         free_dhdr(&dhdr);
  498.         if(addr != 0xffffffff)
  499.             break;
  500.     }
  501.     free(sname);
  502.     if(addr == 0xffffffff)
  503.         addr = 0;
  504.     return addr;
  505. }
  506. /* Send a query to a server */
  507. static int
  508. sendquery(server,name,type,timeout,bpp)
  509. int32 server;        /* Server's IP address */
  510. char *name;        /* Domain name being looked up */
  511. int type;        /* Type of resource record sought */
  512. int32 timeout;        /* Query timeout */
  513. struct mbuf **bpp;    /* Place to stash reply */
  514. {
  515.     char *buf;
  516.     int len;
  517.     struct sockaddr_in server_in;
  518.     int s,rval;
  519.  
  520.     s = socket(AF_INET,SOCK_DGRAM,0);
  521.     buf = mallocw(512);
  522.     len = res_mkquery(0,name,CLASS_IN,TYPE_A,NULLCHAR,0,0,buf,512);
  523.     server_in.sin_family = AF_INET;
  524.     server_in.sin_port = IPPORT_DOMAIN;
  525.     server_in.sin_addr.s_addr = server;
  526.     if(Ddebug){
  527.         printf("resolve: querying server %s for %s\n",
  528.          inet_ntoa(server),name);
  529.     }
  530.     sendto(s,buf,len,0,(char *)&server_in,sizeof(server_in));
  531.     free(buf);
  532.     alarm(max(timeout,1));
  533.     /* Wait for something to happen */
  534.     rval = recv_mbuf(s,bpp,0,NULLCHAR,0);
  535.     alarm(0L);
  536.     close_s(s);
  537.     return rval;
  538. }
  539.  
  540. static int
  541. res_mkquery(op,dname,class,type,data,datalen,newrr,buffer,buflen)
  542. int16 op;    /* operation */
  543. char *dname;    /* Domain name */
  544. int16 class;    /* Class of inquiry (IN, etc) */
  545. int16 type;    /* Type of inquiry (A, MX, etc) */
  546. char *data;
  547. int16 datalen;
  548. int16 newrr;
  549. char *buffer;    /* Area for query */
  550. int16 buflen;    /* Length of same */
  551. {
  552.     char *cp,*cp1;
  553.     int16 parameter;
  554.     int16 dlen,len;
  555.  
  556.     cp = buffer;
  557.     cp = put16(cp,(int16)Clock);    /* Use clock for timestamping */
  558.     parameter = 0x100;    /* Recursion desired */
  559.     cp = put16(cp,parameter);
  560.     cp = put16(cp,1);
  561.     cp = put16(cp,0);
  562.     cp = put16(cp,0);
  563.     cp = put16(cp,0);
  564.     dlen = strlen(dname);
  565.     for(;;){
  566.         /* Look for next dot */
  567.         cp1 = strchr(dname,'.');
  568.         if(cp1 != NULLCHAR)
  569.             len = cp1-dname;    /* More to come */
  570.         else
  571.             len = dlen;    /* Last component */
  572.         *cp++ = len;        /* Write length of component */
  573.         if(len == 0)
  574.             break;
  575.         /* Copy component up to (but not including) dot */
  576.         strncpy(cp,dname,len);
  577.         cp += len;
  578.         if(cp1 == NULLCHAR){
  579.             *cp++ = 0;    /* Last one; write null and finish */
  580.             break;
  581.         }
  582.         dname += len+1;
  583.         dlen -= len+1;
  584.     }
  585.     cp = put16(cp,type);
  586.     cp = put16(cp,class);
  587.     return cp - buffer;
  588. }
  589. /* Append any non-duplicate resource records to the local file */
  590. static void
  591. cache_response(dhdr)
  592. struct dhdr *dhdr;
  593. {
  594.     FILE *fp;
  595.     int i;
  596.     long ttl = 500;    /* Default TTL for negative records without SOA */
  597.     struct rr *rrp,*frrp;
  598.     struct quest *qp;
  599.  
  600.     fp = fopen(Dfile,APPEND_TEXT);
  601.     if(fp == NULLFILE){
  602.         printf("Can't append to %s!!\n",Dfile);
  603.         return;
  604.     }
  605.     /* Scan domain file looking for duplicates */
  606.     while((frrp = getrr(fp)) != NULLRR){
  607.         for(i=0;i< dhdr->ancount;i++){
  608.             rrp = dhdr->ans[i];
  609.             if(rrp->type == TYPE_SOA)
  610.                 ttl = rrp->ttl;
  611.             if(rrcmp(rrp,frrp) == 0)
  612.                 rrp->dupe = 1;
  613.         }
  614.         for(i=0;i< dhdr->nscount;i++){
  615.             rrp = dhdr->ns[i];
  616.             if(rrp->type == TYPE_SOA)
  617.                 ttl = rrp->ttl;
  618.             if(rrcmp(rrp,frrp) == 0)
  619.                 rrp->dupe = 1;
  620.         }
  621.         for(i=0;i< dhdr->arcount;i++){
  622.             rrp = dhdr->add[i];
  623.             if(rrp->type == TYPE_SOA)
  624.                 ttl = rrp->ttl;
  625.             if(rrcmp(rrp,frrp) == 0)
  626.                 rrp->dupe = 1;
  627.         }
  628.         free_rr(frrp);
  629.     }
  630.     /* Now append any non-duplicate records */
  631.     fseek(fp,0L,2);
  632.     for(i=0;i< dhdr->ancount;i++){
  633.         rrp = dhdr->ans[i];
  634.         if(!rrp->dupe)
  635.             putrr(fp,rrp);
  636.     }
  637.     for(i=0;i< dhdr->nscount;i++){
  638.         rrp = dhdr->ns[i];
  639.         if(!rrp->dupe)
  640.             putrr(fp,rrp);
  641.     }
  642.     for(i=0;i< dhdr->arcount;i++){
  643.         rrp = dhdr->add[i];
  644.         if(!rrp->dupe)
  645.             putrr(fp,rrp);
  646.     }
  647.     if(dhdr->aa && (dhdr->rcode == NAME_ERROR || dhdr->ancount == 0)){
  648.         /* Add negative reply to file. This assumes that there was
  649.          * only one question, which is true for all questions we send.
  650.          */
  651.         qp = dhdr->qlist[0];
  652.         rrp = (struct rr *)callocw(1,sizeof(struct rr));
  653.         rrp->name = strdup(qp->qname);
  654.         rrp->type = qp->qtype;
  655.         rrp->class = qp->qclass;
  656.         rrp->ttl = ttl;
  657.         rrp->rdlength = 0;    /* no data */
  658.         putrr(fp,rrp);
  659.         free_rr(rrp);
  660.     }
  661.     fclose(fp);
  662. }
  663. /* Print a resource record */
  664. static void
  665. putrr(fp,rrp)
  666. FILE *fp;
  667. struct rr *rrp;
  668. {
  669.     if(fp == NULLFILE || rrp == NULLRR)
  670.         return;
  671.  
  672.     fprintf(fp,"%s\t%lu",rrp->name,rrp->ttl);
  673.     if(rrp->class == CLASS_IN)
  674.         fprintf(fp,"\tIN");
  675.     else
  676.         fprintf(fp,"\t%u",rrp->class);
  677.     if(rrp->type < Ndtypes)
  678.         fprintf(fp,"\t%s",Dtypes[rrp->type]);
  679.     else
  680.         fprintf(fp,"\t%u",rrp->type);
  681.     if(rrp->rdlength == 0){
  682.         /* Null data portion, indicates nonexistent record */
  683.         fprintf(fp,"\n");
  684.         return;
  685.     }
  686.     switch(rrp->type){
  687.     case TYPE_CNAME:
  688.     case TYPE_MB:
  689.     case TYPE_MG:
  690.     case TYPE_MR:
  691.     case TYPE_NS:
  692.     case TYPE_PTR:
  693.     case TYPE_TXT:
  694.         /* These are all printable text strings */
  695.         fprintf(fp,"\t%s\n",rrp->rdata.data);
  696.         break;
  697.     case TYPE_A:
  698.         fprintf(fp,"\t%s\n",inet_ntoa(rrp->rdata.addr));
  699.         break;
  700.     case TYPE_MX:
  701.         fprintf(fp,"\t%u\t%s\n",rrp->rdata.mx.pref,
  702.          rrp->rdata.mx.exch);
  703.         break;
  704.     case TYPE_SOA:
  705.         fprintf(fp,"\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu\n",
  706.          rrp->rdata.soa.mname,rrp->rdata.soa.rname,
  707.          rrp->rdata.soa.serial,rrp->rdata.soa.refresh,
  708.          rrp->rdata.soa.retry,rrp->rdata.soa.expire,
  709.          rrp->rdata.soa.minimum);
  710.         break;
  711.     default:
  712.         fprintf(fp,"\n");
  713.         break;
  714.     }
  715. }
  716. /* Free a domain message */
  717. static void
  718. free_dhdr(dp)
  719. struct dhdr *dp;
  720. {
  721.     int i;
  722.  
  723.     if(dp->qdcount != 0){
  724.         for(i=0;i<dp->qdcount;i++)
  725.             free_qu(dp->qlist[i]);
  726.         free((char *)dp->qlist);
  727.     }
  728.     if(dp->ancount != 0){
  729.         for(i=0;i<dp->ancount;i++)
  730.             free_rr(dp->ans[i]);
  731.         free((char *)dp->ans);
  732.     }
  733.     if(dp->nscount != 0){
  734.         for(i=0;i<dp->nscount;i++)
  735.             free_rr(dp->ns[i]);
  736.         free((char *)dp->ns);
  737.     }
  738.     if(dp->arcount != 0){
  739.         for(i=0;i<dp->arcount;i++)
  740.             free_rr(dp->add[i]);
  741.         free((char *)dp->add);
  742.     }
  743. }
  744.  
  745. /* Free a question record */
  746. static void
  747. free_qu(qp)
  748. struct quest *qp;
  749. {
  750.     free(qp->qname);
  751.     free((char *)qp);
  752. }
  753.  
  754. /* Free a resource record */
  755. static void
  756. free_rr(rrp)
  757. struct rr *rrp;
  758. {
  759.     if(rrp == NULLRR)
  760.         return;
  761.     free(rrp->name);
  762.     if(rrp->rdlength != 0){
  763.         switch(rrp->type){
  764.         case TYPE_CNAME:
  765.         case TYPE_MB:
  766.         case TYPE_MG:
  767.         case TYPE_MR:
  768.         case TYPE_NS:
  769.         case TYPE_PTR:
  770.             free(rrp->rdata.name);
  771.             break;
  772.         case TYPE_A:
  773.             break;    /* Nothing allocated in rdata section */
  774.         case TYPE_HINFO:
  775.             free(rrp->rdata.hinfo.cpu);
  776.             free(rrp->rdata.hinfo.os);
  777.             break;
  778.         case TYPE_MX:
  779.             free(rrp->rdata.mx.exch);
  780.             break;
  781.         case TYPE_SOA:
  782.             free(rrp->rdata.soa.mname);
  783.             free(rrp->rdata.soa.rname);
  784.             break;
  785.         case TYPE_TXT:
  786.             free(rrp->rdata.data);
  787.             break;
  788.         }
  789.     }
  790.     free((char *)rrp);
  791. }
  792. /* Compare two resource records, returning 0 if equal, nonzero otherwise */
  793. static int
  794. rrcmp(rr1,rr2)
  795. register struct rr *rr1,*rr2;
  796. {
  797.     int i;
  798.  
  799.     if(rr1 == NULLRR || rr2 == NULLRR)
  800.         return -1;
  801.     if((i = strlen(rr1->name)) != strlen(rr2->name))
  802.         return 1;
  803.     if((i = strnicmp(rr1->name,rr2->name,i)) != 0)
  804.         return i;
  805.     if(rr1->type != rr2->type)
  806.         return 2;
  807.     if(rr1->class != rr2->class)
  808.         return 3;
  809.     /* Note: rdlengths are not compared because they vary depending
  810.      * on the representation (ASCII or encoded) this record was
  811.      * generated from.
  812.      */
  813.     switch(rr1->type){
  814.     case TYPE_A:
  815.         i = rr1->rdata.addr != rr2->rdata.addr;
  816.         break;
  817.     case TYPE_SOA:
  818.         i = rr1->rdata.soa.serial != rr2->rdata.soa.serial;
  819.         break;
  820.     case TYPE_HINFO:
  821.         i = strcmp(rr1->rdata.hinfo.cpu,rr2->rdata.hinfo.cpu) ||
  822.             strcmp(rr1->rdata.hinfo.os,rr2->rdata.hinfo.os);
  823.         break;
  824.     case TYPE_MX:
  825.         i = strcmp(rr1->rdata.mx.exch,rr2->rdata.mx.exch);
  826.         break;
  827.     case TYPE_MB:
  828.     case TYPE_MG:
  829.     case TYPE_MR:
  830.     case TYPE_NULL:
  831.     case TYPE_WKS:
  832.     case TYPE_PTR:
  833.     case TYPE_MINFO:
  834.     case TYPE_TXT:
  835.     case TYPE_NS:
  836.         i = strcmp(rr1->rdata.data,rr2->rdata.data);
  837.         break;
  838.     case TYPE_MD:
  839.     case TYPE_MF:
  840.     case TYPE_CNAME:
  841.         i = strcmp(rr1->rdata.data,rr2->rdata.data);
  842.         break;
  843.     }
  844.     return i;
  845. }
  846. /* Return 1 if string appears to be an IP address in dotted decimal;
  847.  * return 0 otherwise (i.e., if string is a domain name)
  848.  */
  849. static int
  850. isaddr(s)
  851. register char *s;
  852. {
  853.     char c;
  854.  
  855.     if(s == NULLCHAR)
  856.         return 1;    /* Can't happen */
  857.  
  858.     while((c = *s++) != '\0'){
  859.         if(!isdigit(c) && c != '.')
  860.             return 0;
  861.     }
  862.     return 1;
  863. }
  864. static void
  865. dumpdomain(dhdr,rtt)
  866. struct dhdr *dhdr;
  867. int32 rtt;
  868. {
  869.     int i;
  870.     struct rr *rrp;
  871.     struct quest *qp;
  872.  
  873.     printf("response id %u (rtt %lu sec) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %u\n",
  874.      dhdr->id,((long)rtt * MSPTICK)/1000,
  875.      dhdr->qr,dhdr->opcode,dhdr->aa,dhdr->tc,dhdr->rd,
  876.      dhdr->ra,dhdr->rcode);
  877.     printf("%u questions:\n",dhdr->qdcount);
  878.     for(i=0;i< dhdr->qdcount;i++){
  879.         qp = dhdr->qlist[i];
  880.         printf("%s type %u class %u\n",qp->qname,
  881.          qp->qtype,qp->qclass);
  882.     }
  883.     printf("%u answers:\n",dhdr->ancount);
  884.     for(i=0;i< dhdr->ancount;i++){
  885.         rrp = dhdr->ans[i];
  886.         putrr(stdout,rrp);
  887.     }
  888.     printf("%u authority:\n",dhdr->nscount);
  889.     for(i=0;i< dhdr->nscount;i++){
  890.         rrp = dhdr->ns[i];
  891.         putrr(stdout,rrp);
  892.     }
  893.     printf("%u additional:\n",dhdr->arcount);
  894.     for(i=0;i< dhdr->arcount;i++){
  895.         rrp = dhdr->add[i];
  896.         putrr(stdout,rrp);
  897.     }
  898.     fflush(stdout);
  899. }
  900.  
  901.